using System;
using System.Collections.Generic;
using System.Reflection;
using OhioState.AssetManaged;
using OhioState.Graphics.Proxy;
using OhioState.Physics;

namespace OhioState.Graphics.OpenGL
{
    public class GLFactory
    {
        //
        // A mapping between IAssetManaged types and thier handlers (OpenGLObject types).
        //
        private static Dictionary<Type, Type> registeredTypes = new Dictionary<Type, Type>();
        //
        // A mapping from the OpenGLObject types and the assembly containing them.
        // This is needed to create instances of the type.
        //
        private static Dictionary<Type, Assembly> assemblies = new Dictionary<Type,Assembly>();

        public static void RegisterTypes(Assembly assembly)
        {
            Type[] types = assembly.GetExportedTypes();
            foreach (Type type in types)
            {
                if (typeof(OpenGLObject).IsAssignableFrom(type))
                {
                    assemblies.Add(type, assembly);
                }
            }
        }

        public static void RegisterHandler(Type assetType, Type handlerType)
        {
            if (assemblies.ContainsKey(handlerType))
            {
                registeredTypes.Add(assetType, handlerType);
            }
        }

        static GLFactory()
        {
            RegisterTypes(Assembly.GetExecutingAssembly());
            //
            // Hack for now, this should come from an initialization file. Note, there
            // should be no restriction that the Handler to Proxy is one to one.
            // Machines with less functionality should be able to switch say a complex light
            // with a point light, or a NURB surface with a stand-in cube object.
            //
            Type assetType;
            Type handlerType;
            assetType = typeof(MaterialProxy);
            handlerType = typeof(MaterialHandler);
            RegisterHandler(assetType, handlerType);
            assetType = typeof(MotionBlurredLayerProxy);
            handlerType = typeof(MotionBlurredLayerHandler);
            RegisterHandler(assetType, handlerType);
            assetType = typeof(VertexShader);
            handlerType = typeof(ShaderRoutineHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(FragmentShader);
            handlerType = typeof(ShaderRoutineHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(ShaderProgram);
            handlerType = typeof(ShaderProgramHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(Volume);
            handlerType = typeof(VolumeHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(Segment);
            handlerType = typeof(SegmentHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(TexImage);
            handlerType = typeof(TexImageHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(LayerProxy);
            handlerType = typeof(LayerHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(ClippedDrawableProxy);
            handlerType = typeof(ClippedDrawableHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(ClipPlaneProxy);
            handlerType = typeof(ClipPlaneHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(ROIBoxProxy);
            handlerType = typeof(ROIBoxHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(BoxOutlineProxy);
            handlerType = typeof(BoxOutlineHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(BoxBoundaryProxy);
            handlerType = typeof(BoxBoundaryHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(SphereProxy);
            handlerType = typeof(SphereHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(RigidBody);
            handlerType = typeof(RigidBodyGL);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(TransferFunction);
            handlerType = typeof(TransferFuncHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(LayerTextureProxy);
            handlerType = typeof(Texture2DHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(Texture2D);
            handlerType = typeof(Texture2DHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(SlicePlaneProxy);
            handlerType = typeof(SlicePlaneHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(AxesPlaneProxy);
            handlerType = typeof(AxesPlaneHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(LightCollectionProxy);
            handlerType = typeof(LightCollectionHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(DirectionalLightProxy);
            handlerType = typeof(DirectionalLightHandler);            
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(VolumeHistogram);
            handlerType = typeof(TexImageHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(ImageHistogram);
            handlerType = typeof(TexImageHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(TransferFunction2D);
            handlerType = typeof(TexImageHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(VolumeGradientHistogram);
            handlerType = typeof(TexImageHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(VectorField);
            handlerType = typeof(TexImageHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(DepthBufferProxy);
            handlerType = typeof(DepthBufferHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(FrameBufferObjectProxy);
            handlerType = typeof(FrameBufferObjectHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(ModelProxy);
            handlerType = typeof(ModelHandler);
            registeredTypes.Add(assetType, handlerType);
            assetType = typeof(VectorField3D);
            handlerType = typeof(VolumeHandler);
            registeredTypes.Add(assetType, handlerType);
        }

        public static OpenGLObject OpenGLFactory (IAssetManaged proxyObject)
        {
            OpenGLObject realObject = null;
            Type proxyType = proxyObject.GetType();
            Type handlerType;
            if (registeredTypes.TryGetValue(proxyType, out handlerType))
            {
                Assembly assembly = assemblies[handlerType];
                object[] contructorArgs = { proxyObject };
                realObject = assembly.CreateInstance(handlerType.FullName, false, BindingFlags.Default, null, contructorArgs, null, null) as OpenGLObject;
            }
            return realObject;
        }    
    }
}